home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Internet Tools 1993 July / Internet Tools.iso / RockRidge / mail / mmdf / mmdf-IIb.43 / uip / snd / s_get.c < prev    next >
Encoding:
C/C++ Source or Header  |  1988-03-28  |  15.8 KB  |  705 lines

  1. /*
  2. **        S _ G E T
  3. **
  4. **
  5. **    R E V I S I O N  H I S T O R Y
  6. **
  7. **    03/31/83  GWH    Split the SEND program into component parts
  8. **            This module contains getuinfo, gethead, prefix,
  9. **            and getaddr.
  10. **
  11. **    04/15/83  DPK    Changed address format from "user at host" to
  12. **            "user@host". Also added call to getmailid() in get
  13. **            getuinfo();
  14. **
  15. **    05/20/83  GWH    Modified getuinfo() to allow a number of user-
  16. **            selectable options. These include the use of a
  17. **            ".sendrc" file on the user's home directory. With
  18. **            the use of the "rc" file the user can set such things
  19. **            default editor, local-alias-file, signature block,
  20. **            and a directory for draft files. Also included is a
  21. **            provision for keeping file copies of messages that
  22. **            are successfully copied (incomplete at this time).
  23. **
  24. **    06/22/83  GWH    Added the required code to addrcat to enable local
  25. **            alias file feature.
  26. **
  27. **    10/21/83  GWH    Fixed a bug in the alias file code (in addrcat).
  28. **            Prevents segmentation faults when loops are found
  29. **            in the alias file definitions.
  30. **
  31. **    11/16/83  DPK    Merged in DPK signature checking and Geo loop catcher
  32. **
  33. **    11/21/83  GWH    Added 'directedit' option.
  34. **
  35. **    03/18/85  DPK    Fixed usage of parsadr function so that after parsing
  36. **          VAK    we now use the components instead of original string.
  37. **
  38. */
  39.  
  40.  
  41. #include <stdio.h>
  42. #include "./s.h"
  43. #include "./s_externs.h"
  44.  
  45. extern char *getmailid();
  46. extern char *malloc();
  47. extern char *strdup();
  48. extern struct passwd *getpwuid();
  49. extern char *mktemp();
  50. extern char *index();
  51. extern char *getenv();
  52.  
  53. extern char *dflveditor;
  54. extern char *dflchecker;
  55.  
  56. #define END    (char *)0
  57.  
  58. struct RCOPTION rcoptions[] = {
  59.     "copyfile", COPYFILE,
  60.     "draftdir", DRAFTDIR,
  61.     "signature", SIGNATURE,
  62.     "nosignature", NOSIGNATURE,
  63.     "replyto", REPLYTO,
  64.     "aliases", ALIASES,
  65.     "subargs", SUBARGS,
  66.     "editor", EDITOR,
  67.     "veditor", VEDITOR,
  68.     "file", CFILE,
  69.     "fileonquery", QFILE,
  70.     "nofile", NOFILE,
  71.     "checker", CHECKER,
  72.     "header", ADDHEADER,
  73.     "paging", PAGING,
  74.     END
  75. };
  76.  
  77. int picko();
  78. int ded = 0;
  79. struct passwd *pw;
  80. char *midp;
  81. char *d_subargs = "vm";
  82. char *tmp_tmplt = "tmpdrft.XXXXXX";
  83. char *drft_tmplt = "drft.XXXXXX";
  84. char linebuf[128];
  85. char tmpline[128];
  86.  
  87. getuinfo() {
  88.     FILE *fp;
  89.     int realid, effecid;
  90.     char *av[NARGS];
  91.     char rcfilename[128];
  92.     register char *p;
  93.     char *rcname = "/.sendrc";
  94.  
  95.     int i;
  96.  
  97.     /* build a draft file name */
  98.  
  99.     mktemp(drft_tmplt);
  100.     mktemp(tmp_tmplt);
  101.  
  102.     /* Who are we this time */
  103.  
  104.     getwho(&realid, &effecid);
  105.  
  106.     /* If nothing found return false. */
  107.  
  108.     if(( pw = getpwuid(effecid)) == NULL  ||
  109.         (midp = getmailid(pw->pw_name)) == NULL )
  110.             return(FALSE);
  111.  
  112.     /* Build a name for this user */
  113. #ifdef PWNAME
  114.     if (p = index( pw->pw_gecos, ',' )) *p = '\0';
  115.     if (p = index( pw->pw_gecos, '<' )) *p = '\0';
  116.     if (p = index( pw->pw_gecos, '&' )) {
  117.         /* Deal with Berkeley folly */
  118.         *p = 0;
  119.         sprintf( from, "%s%c%s%s <%s@%s.%s>", pw->pw_gecos,
  120.              lowtoup( pw->pw_name[0] ),
  121. #ifdef JNTMAIL
  122.              pw->pw_name+1, p+1, midp, ap_dmflip(locdomain), locname );
  123.     } else
  124.         sprintf( from, "%s <%s@%s.%s>", pw->pw_gecos, midp, ap_dmflip(locdomain), locname);
  125. #else JNTMAIL
  126.             pw->pw_name+1, p+1, midp, locname, locdomain);
  127.     } else
  128.         sprintf( from, "%s <%s@%s.%s>", pw->pw_gecos, midp, locname, locdomain );
  129. #endif JNTMAIL
  130. #else
  131.     sprintf( from, "%c%s@%s.%s",    /* default from text */
  132. #ifdef JNTMAIL
  133.         lowtoup( midp[0] ), &(midp[1]), ap_dmflip(locdomain), locname);
  134. #else JNTMAIL
  135.         lowtoup( midp[0] ), &( midp[1] ), locname, locdomain );
  136. #endif JNTMAIL
  137. #endif
  138.     /* Set default values for those options that need defaults */
  139.  
  140.     strcpy(editor, ((p = getenv("VISUAL")) && *p) ? p : 
  141.                  (((p = getenv("EDITOR")) && *p) ? p : dflveditor));
  142.     strcpy(checker, dflchecker);
  143.     sprintf(linebuf, "%s/.sent", pw->pw_dir);
  144.     strcpy(copyfile, linebuf);
  145.     sprintf(drffile, "%s/%s", pw->pw_dir, drft_tmplt);
  146.      sprintf(tmpdrffile, "%s/%s", pw->pw_dir, tmp_tmplt);
  147.     strcpy( subargs, d_subargs );
  148.     wflag = 0;
  149.     cflag = 0;
  150.     rflag = 0;
  151.     qflag = 0;
  152.     pflag = 0;
  153.            strcpy (signature, from);
  154.     /* Get info from the ".sendrc" file */
  155.  
  156.     sprintf( rcfilename, "%s/%s", pw->pw_dir, rcname );
  157.     if(( fp = fopen(rcfilename, "r")) != NULL ) {
  158.         char *cp;
  159.  
  160.         /* Process info a line at a time */
  161.         while( fgets(linebuf, sizeof(linebuf), fp ) != NULL ) {
  162.             if (cp = index(linebuf, '\n'))
  163.                 *cp = 0;
  164.             if (sstr2arg(linebuf, NARGS, av, " \t") < 0)
  165.                 continue;
  166.             if( (i=picko(av[0])) < 0)
  167.                 continue; /* bad option */
  168.             select_o( i, av );
  169.         }    /* end of while on lines */
  170.     }    /* end of if statement on file open */
  171.  
  172.     return(TRUE);
  173. }    /* end of getuinfo routine */
  174.  
  175. /* select an option */
  176.  
  177. picko (pp)
  178. char **pp;
  179. {
  180.     struct RCOPTION *rcopt;
  181.  
  182.     rcopt = rcoptions;
  183.     while(rcopt->name != END ) {
  184.         if( lexequ( rcopt->name, pp ) )
  185.             return(rcopt->idnum);
  186.         rcopt++;
  187.     }
  188.  
  189.     return(-1); /* no match */
  190. }
  191.  
  192. select_o (key, pp)
  193. int key;
  194. char **pp;
  195. {
  196.     register char *p;
  197.     char *akey, *list;
  198.     char tmpbuf[512];
  199.  
  200.     switch( key ) {
  201.     case COPYFILE:
  202.         /* Pick a file to store file copies of sent messages */
  203.         if( *(++pp) == NULL )
  204.         {
  205.             fprintf(stderr,"You need to specify a copy file in your .sendrc.\n");
  206.             fprintf(stderr,"Defaulting to '.sent'\n");
  207.         }
  208.         else
  209.         {
  210.             strcpy( copyfile, *pp);
  211.             if( copyfile[0] != '/' ) 
  212.             {
  213.                 strcpy(tmpline, copyfile);
  214.                 sprintf(copyfile, "%s/%s",pw->pw_dir,tmpline);
  215.             }
  216.         }
  217.         break;
  218.  
  219.     case DRAFTDIR:
  220.         /* pickup the draft directory */
  221.         if( *(++pp) != NULL )
  222.         {
  223.             sprintf( drffile, "%s/%s", *pp, drft_tmplt );
  224.             sprintf( tmpdrffile, "%s/%s", *pp, tmp_tmplt );
  225.         }
  226.         else
  227.         {
  228.             sprintf( drffile, "%s/%s", pw->pw_dir, drft_tmplt);
  229.             sprintf( tmpdrffile, "%s/%s", pw->pw_dir, tmp_tmplt);
  230.         }
  231.         break;
  232.  
  233.     case SIGNATURE:
  234.         /* If he wants a signature block use it */
  235.         if( *(++pp) == 0 ){
  236. #ifdef PWNAME
  237.             sprintf( signature, "%c%s@%s.%s", /* use his login name alone */
  238. #ifdef JNTMAIL
  239.                lowtoup(midp[0]), &(midp[1]), ap_dmflip(locdomain), locname );
  240. #else JNTMAIL
  241.                lowtoup(midp[0]), &(midp[1]), locname, locdomain );
  242. #endif JNTMAIL
  243. #else
  244.             strcpy( signature, from );    /* NO-OP ? */
  245. #endif
  246.         } else {
  247.             linebuf[0] = '\0';
  248.             while( *pp != 0){
  249.                 strcat(linebuf, *pp);
  250.                 strcat(linebuf, " ");
  251.                 *pp++;
  252.             }
  253.             if (checksignature (linebuf) == 0) {
  254. #ifdef JNTMAIL
  255.                 sprintf(tmpline, "%s.%s", ap_dmflip(locdomain), locname);
  256. #else JNTMAIL
  257.                 sprintf(tmpline, "%s.%s", locname, locdomain);
  258. #endif JNTMAIL
  259.                 for( p=tmpline ; *p ; p++)
  260.                     *p = uptolow(*p);
  261.                 sprintf( signature, "%s <%s@%s>",
  262.                    linebuf, midp, tmpline);
  263.             } else {
  264.                 fprintf(stderr,"Illegal signature, using default\n");
  265.             }
  266.         }
  267.         break;
  268.  
  269.     case NOSIGNATURE:
  270. #ifdef PWNAME
  271.         sprintf( signature, "%c%s@%s.%s", /* use his login name alone */
  272. #ifdef JNTMAIL
  273.                lowtoup(midp[0]), &(midp[1]), ap_dmflip(locdomain), locname );
  274. #else JNTMAIL
  275.                lowtoup(midp[0]), &(midp[1]), locname, locdomain);
  276. #endif JNTMAIL
  277. #else
  278.         strcpy( signature, from );
  279. #endif
  280.         break;
  281.  
  282.     case REPLYTO:
  283.         rflag = 1;
  284.         break;
  285.  
  286.     case ALIASES:
  287.         if( *(++pp) == NULL )
  288.             fprintf(stderr,"You need to specify an alias file name!\n");
  289.         else
  290.         {
  291.             strcpy( aliasfilename, *pp );
  292.             if( aliasfilename[0] != '/' ) 
  293.             {
  294.                 strcpy(tmpline, aliasfilename);
  295.                 sprintf(aliasfilename, "%s/%s",pw->pw_dir,tmpline);
  296.             }
  297.         }
  298.         aliasinit( aliasfilename );
  299.         break;
  300.  
  301.     case SUBARGS:
  302.         while( *(++pp) != NULL )
  303.             strcat(subargs, *pp);
  304.         wflag = 1;
  305.         break;
  306.     case EDITOR:
  307.         if(ded)
  308.             break;
  309.         else if( *(++pp) == NULL )
  310.         {
  311.             fprintf(stderr,"You need to specify an editor after 'editor' in your .sendrc.\n");
  312.             fprintf(stderr,"Defaulting to %s.\n",editor);
  313.         }
  314.         else
  315.             strcpy( editor, *pp );
  316.         break;
  317.     case VEDITOR:
  318.         /* Default editor for use with the "e" command */
  319.         if( *(++pp) == NULL )
  320.         {
  321.             fprintf(stderr,"You need to specify an editor with the veditor in your .sendrc.\n");
  322.             fprintf(stderr,"Defaulting to %s.\n",editor);
  323.         }
  324.         else
  325.             strcpy( editor, *pp );
  326.         ded = 1;
  327.         break;
  328.  
  329.     case CHECKER:
  330.         /* Default spelling checker for use with the "c" command */
  331.         if( *(++pp) == NULL )
  332.         {
  333.             fprintf(stderr,"You need to specify a spelling checker after 'checker' in your .sendrc.\n");
  334.             fprintf(stderr,"Defaulting to %s.\n",checker);
  335.         }
  336.         else
  337.             strcpy( checker, *pp );
  338.         break;
  339.  
  340.        case PAGING : 
  341.            /* Turn on paging during message review */
  342.            pflag = 1;
  343.            break;
  344.  
  345.     case CFILE:
  346.         cflag = 1;
  347.         break;
  348.  
  349.     case QFILE:
  350.         qflag = 1;
  351.         /* DROP */
  352.     case NOFILE:
  353.         cflag = 0;
  354.         break;
  355.  
  356.     case ADDHEADER:
  357.         /* Add a header line to the message */
  358.         ++pp;
  359.         if (isstr(*pp))
  360.             addheader(pp[0], pp[1]);
  361.         break;
  362.  
  363.     default:
  364.         fprintf(stderr,"GETUINFO - NO SUCH OPTION key = %d\n", key);
  365.  
  366.     } /* end of switch */
  367. }
  368. /* Prompts for a header with print as prompt and gathers it up */
  369.  
  370. gethead (print, buf, flag)
  371. char    print[];
  372. register char   *buf;
  373. int     flag;                     /* print contents, if any?            */
  374. {
  375.     char    c;
  376.     int retval;                   /* type of FLD modification           */
  377.     register int    n;
  378.     register int    max = S_BSIZE;
  379.  
  380.     if (flag && *buf)             /* print what already is there        */
  381.     printf (shrtfmt, print, buf);
  382.  
  383.     flag = TRUE;                  /* always & only look at first char   */
  384.     do
  385.     {
  386.     printf ("%s", print);     /* prompt                             */
  387.     if (*buf == '\\')
  388.     {
  389.         *buf++ = ',';
  390.         *buf++ = '\n';
  391.     }
  392.     fflush (stdout);
  393.  
  394.     if (flag)
  395.     {
  396.         flag = FALSE;         /* ignore first char of next lines    */
  397.         switch (c = getchar ())
  398.         {
  399.         case '-':         /* delete single name                */
  400.             retval = ITMRMV;
  401.             break;
  402.         case '#':         /* delete all contents     */
  403.             *buf = 0;
  404.             while (getchar () != '\n');
  405.             return (FLDREMV);
  406.  
  407.         case '\n':        /* leave it as it is                  */
  408.             return (FLDSAME);
  409.  
  410.         case '+':         /* append to end of field             */
  411.             retval = FLDADD;
  412.             if (*buf != '\0')
  413.             {                 /*   if not already empty             */
  414.             buf = &buf[strlen (buf)];
  415.                       /* point to end of buf                */
  416.             *buf++ = ','; /* assume it's an address field       */
  417.             *buf++ = ' ';
  418.             max -= 2;
  419.             }
  420.             break;
  421.  
  422.         default:          /* copy over it                       */
  423.             retval = FLDOVER;
  424.             *buf++ = c;
  425.             max--;
  426.             break;
  427.         }
  428.     }
  429.     n = gather (buf, max);    /* get rest of header line            */
  430.     max -= n;
  431.     buf = &buf[n - 1];
  432.     }
  433.     while (*buf == '\\');         /* user wants to add more?            */
  434.     return (retval);
  435. }
  436.  
  437. prefix (buf, pre)
  438. char   *buf,
  439.        *pre;
  440. {
  441.     while (*pre)
  442.     if (*buf++ != *pre++)
  443.         return (FALSE);
  444.     return (TRUE);
  445. }
  446.  
  447.  
  448. getaddr (print, buf, flag, defhost)
  449.     char print[];
  450.     char *buf;
  451.     int flag;
  452.     char defhost[];
  453. {
  454.     char addrin[S_BSIZE];     /* temporary store for user input     */
  455.     char    *dn, *gstrindex();
  456.  
  457.     if (flag && *buf)             /* print what already is there        */
  458.     printf (shrtfmt, print, buf);
  459.  
  460.     addrin[0] = '\0';             /* mark temp buffer as empty          */
  461.     switch (gethead (print, addrin, NO))
  462.     {
  463.     case FLDREMV:             /* erase any existing contents        */
  464.         buf[0] = '\0';
  465.         break;
  466.  
  467.     case ITMRMV:         /* delete single name            */
  468.         dn = gstrindex(addrin, buf);
  469.         if(dn == 0){
  470.             fprintf(stderr," no such name in the list; name = '%s'\n",addrin);
  471.             break;
  472.         }
  473.         dlt_name( buf, dn );
  474.         break;
  475.     case FLDSAME:             /* leave as is                        */
  476.         break;
  477.  
  478.     case FLDOVER:             /* overwrite existing contents        */
  479.         buf[0] = '\0';        /* erase existing, then add           */
  480.         aliasmap(buf, addrin, defhost);
  481.         break;
  482.  
  483.     case FLDADD:              /* append to existing                 */
  484.         aliasmap(buf, addrin, defhost);
  485.         break;
  486.     }
  487. }
  488.  
  489. /*
  490. **    S P E C I A L  S T R I N D E X  F U N C T I O N
  491. **
  492. ** Specially modified by George Hartwig to return a pointer to the beginning
  493. ** of the requested string instead of the offset.
  494. */
  495.  
  496. char *gstrindex (str, target)           /* return column str starts in target */
  497. register char   *str,
  498.         *target;
  499. {
  500.     char *otarget;
  501.     register short slen;
  502.  
  503.     for (otarget = target, slen = strlen (str); ; target++)
  504.     {
  505.     if (*target == '\0')
  506.         return ((char *) 0);
  507.  
  508.     if (equal (str, target, slen))
  509.         return( target );
  510.     }
  511. }
  512. dlt_name(buf, pos)
  513. char *buf, *pos;
  514.  
  515. /* buf is a pointer to a character array and pos is a pointer to a position  */
  516. /* within that array. The purpose of this routine is delete the name field   */
  517. /* pointed to by pos. In order to do this we will search backward to either  */
  518. /* comma ',' or a colon ':' (if a comma, we will then delete that comma also */
  519. /* and then delete forward until another comma or                  */
  520. /* a end-of-string '\0' is found.                          */
  521.  
  522. {
  523.     char tmpbuffer[S_BSIZE];
  524.     char *sd, *ed, *cp;
  525.     int quote_flag;
  526.  
  527.  
  528.     cp = pos;
  529.     quote_flag = 0;
  530.  
  531.     while(cp >= buf ) {
  532.         if( *cp == '"' )
  533.             if( quote_flag == 0 )
  534.                 quote_flag = 1;
  535.             else
  536.                 quote_flag = 0;
  537.         if( *cp == ',' && quote_flag == 0 )
  538.             break;
  539.         else
  540.             cp--;
  541.     }
  542.     sd = cp;
  543.  
  544.     cp = pos;
  545.  
  546.     while( *cp != '\0' ) {
  547.         if( *cp == '"' )
  548.             if( quote_flag == 0 )
  549.                 quote_flag = 1;
  550.             else
  551.                 quote_flag = 0;
  552.         if( *cp == ',' && quote_flag == 0 )
  553.             break;
  554.         else
  555.             cp++;
  556.     }
  557.  
  558.     ed = cp;
  559.  
  560.     /* at this point *sd should point at the comma preceding the name
  561.     ** to be deleted or the beginning of the line and ed should be
  562.     ** pointing to the trailing comma or the end of the line. So it is
  563.     ** necessary at this point to determine just which of these cases
  564.     ** have occurred so that the string may be properly reassembled.
  565.     */
  566.  
  567.     if( *sd == ',' && *ed == ',' ){
  568.         sd++;
  569.         *sd = '\0';
  570.         ed++;
  571.         sprintf( tmpbuffer, "%s%s", buf, ed);
  572.     }
  573.  
  574.     else
  575.     if( sd <= buf ){
  576.         ed++;
  577.         strcpy(tmpbuffer, ed);
  578.     }
  579.     else
  580.     if( *ed == '\0' ){
  581.         *sd = '\0';
  582.         strcpy(tmpbuffer, buf);
  583.     }
  584.     strcpy( buf, tmpbuffer );
  585. }
  586.  
  587. /*
  588.  *    checksignature ()
  589.  *
  590.  *  Verifies that the signature string does not contain any special
  591.  *  characters or is quoted.  Also checks for blank "name" portion.
  592.  */
  593. checksignature (sp)
  594. register char *sp;
  595. {
  596.     char tptr[128], *savptr, *ptr;
  597.     char *rindex();
  598.     static char quote[] = "\"";
  599.     
  600.     savptr = sp;
  601.     while (*sp && isspace(*sp))  /* eat leading whitespace */
  602.         sp++;
  603.     if (*sp == '\0') {
  604.         fprintf(stderr,"Signature is blank\n");
  605.         return (-1);     /* must have some signature */
  606.     }
  607.     while (*sp) {
  608.         switch (*sp) {
  609.         case '<':
  610.         case '>':
  611.         case '@':
  612.         case ',':
  613.         case ';':
  614.         case ':':
  615.         case '.':    /*  Arggggg...  */
  616.         case '[':
  617.         case ']':
  618.             /* surround bad signature with quotes */
  619.             tptr[0] = '\0';
  620.             strcat( tptr, quote );
  621.             sp = savptr;
  622.             strcat( tptr, sp );
  623.             if( ptr = rindex( tptr, ' ' ) )
  624.                 *ptr = '\0';
  625.             strcat( tptr, quote );
  626.             strcpy( sp, tptr );
  627.             return( 0 );
  628.  
  629.         case '\\':
  630.             sp++;
  631.             if (*sp == '\0')
  632.                 return (-1);
  633.             break;
  634.  
  635.         case '"':
  636.             for (sp++; *sp != '"'; sp++) {
  637.                 if (*sp == '\\') {
  638.                     sp++;
  639.                     if (*sp == '\0')
  640.                         return (-1);
  641.                 } else if (*sp == '\0') {
  642.                     fprintf(stderr,"Unmatched '\"' in signature\n");
  643.                     return (-1);
  644.                 }
  645.             }
  646.             break;
  647.  
  648.         default:
  649.             break;
  650.         }
  651.         sp++;
  652.     }
  653.  
  654.     return (0);
  655. }
  656.  
  657. addheader(name, data)
  658. char    *name;
  659. char    *data;
  660. {
  661.     register struct header *nhp;
  662.     register struct header *ohp;
  663.     register char *cp;
  664.     char    buf[LINESIZE];
  665.  
  666.     if(!isstr(name))
  667.         return;
  668.     for (cp = name; *cp; cp++)
  669.         if (!isprint(*cp) && *cp != '\t') {
  670.             fprintf(stderr,"Illegal character in header name.\n");
  671.             return;
  672.         }
  673.     data = (isstr(data) ? data : "");
  674.     for (cp = data; *cp; cp++)
  675.         if (!isprint(*cp) && *cp != '\t') {
  676.             fprintf(stderr,"Illegal character in header data.\n");
  677.             return;
  678.         }
  679.     if (headers) {
  680.         for (ohp = headers; !lexequ(name, ohp->hname); ohp = ohp->hnext)
  681.             if (ohp->hnext == (struct header *)0)
  682.                 break;
  683.         if(lexequ(name, ohp->hname)) {
  684.             strncpy(ohp->hdata, data, sizeof(ohp->hdata)-1);
  685.             return;
  686.         }
  687.     }
  688.     nhp = (struct header *)malloc(sizeof (*nhp));
  689.     sprintf(buf, "%s:  ", name);
  690.     if (nhp == NULL || (nhp->hname = strdup(buf)) == NULL) {
  691.         fprintf(stderr,"No memory for header '%s'\n", buf);
  692.         if (nhp)
  693.             free(nhp);
  694.         return;
  695.     }
  696.     strncpy(nhp->hdata, data, sizeof(nhp->hdata)-1);
  697.     nhp->hnext = (struct header *)0;
  698.     nhp->hdata[sizeof(nhp->hdata)-1] = '\0';
  699.     if (headers == (struct header *)0) {
  700.         headers = nhp;
  701.         return;
  702.     }
  703.     ohp->hnext = nhp;
  704. }
  705.